home *** CD-ROM | disk | FTP | other *** search
/ Workbench Design / WB Collection.iso / workbench werkzeuge / memory & system tools / memminister / source / memminister.c < prev    next >
C/C++ Source or Header  |  1996-04-07  |  18KB  |  520 lines

  1. /*
  2. **  MemMinister is copyright by Marcus Ohlström 1994-1995. All rights reserved
  3. */
  4.  
  5. #include "memminister.h"
  6.  
  7. IMPORT UBYTE *ver ;
  8.  
  9. LONG __oslibversion = 36 ;
  10.  
  11. void __regargs __chkabort(void);
  12. void __regargs __chkabort(void){}  /* Oskadliggör hanteringen av CTRL-C */
  13.  
  14. struct TextAttr textattr ;  /* initieras av layoutAll() */
  15.  
  16. UWORD snap_borData[2][6] ;  /*  kommer enligt ANSI-standard 0-initialiseras  */
  17. UWORD flush_borData[2][6] ; /*  kommer enligt ANSI-standard 0-initialiseras  */
  18.  
  19. struct Border snap_bor[] = 
  20. {
  21.     { 0, 0, 2, 0, JAM1, 3, snap_borData[0], &snap_bor[1] },
  22.     { 0, 0, 1, 0, JAM1, 3, snap_borData[1], NULL }
  23. } ;
  24.  
  25. struct Border flush_bor[] = 
  26. {
  27.     { 0, 0, 2, 0, JAM1, 3, flush_borData[0], &flush_bor[1] },
  28.     { 0, 0, 1, 0, JAM1, 3, flush_borData[1], NULL }
  29. } ;
  30.  
  31. struct IntuiText snap_gadText[] = 
  32. {
  33.     { 1, 0, JAM2, 10, 2, &textattr, "Free",     &snap_gadText[1] },
  34.     { 1, 0, JAM2, 45, 2, &textattr, "Snapped",  &snap_gadText[2] },
  35.     { 1, 0, JAM2, 90, 2, &textattr, "Used",     NULL },
  36. } ;
  37.  
  38. struct IntuiText flush_gadText =
  39.     { 1, 0, JAM2, 4,  2, &textattr, "Flush",    NULL } ;
  40.  
  41. struct Gadget snap_gad =  { NULL,     54, 12, 100, 12, GFLG_GADGHCOMP, GACT_RELVERIFY, GTYP_BOOLGADGET,  &snap_bor, NULL,   snap_gadText, NULL, NULL,  SNAP_GAD, NULL } ;
  42. struct Gadget flush_gad = { &snap_gad, 4, 12,  28, 12, GFLG_GADGHCOMP, GACT_RELVERIFY, GTYP_BOOLGADGET, &flush_bor, NULL, &flush_gadText, NULL, NULL, FLUSH_GAD, NULL } ;
  43.  
  44. struct Image image ; /*  kommer enligt ANSI-standard 0-initialiseras  */
  45.  
  46. ULONG chip_snapped, fast_snapped, old_chip_free, old_fast_free ;
  47.  
  48. /*  nedanstående initieras i layouotAll()  */
  49. ULONG chip_XPos, fast_XPos, total_XPos ;
  50. ULONG chip_YPos, fast_YPos, total_YPos ;
  51. ULONG text_RightX, free_RightX, snapped_RightX, used_RightX ;
  52. LONG number_length ;
  53.  
  54. UBYTE *chip_text = "Chip" , *fast_text = "Fast", *total_text = "Total" ;
  55.  
  56. UBYTE str[11] ; /* <-  11 istället för STRLEN gör att fönstret ser        */
  57.                 /* konstigt ut om STRLEN är för litet, men programmet     */
  58.                 /* krashar inte!! (Vilket det gör om det står STRLEN här) */
  59.  
  60. struct IntuiText iText = { 1, 0, JAM2, 0, 0, &textattr, str, NULL } ;
  61.  
  62. struct Window *win ;
  63. struct Screen *scr ;
  64.  
  65. /*  värden som kan förändras mha tooltypes  */
  66. WORD zoomsize[4] ; /*  kommer enligt ANSI-standard 0-initialiseras  */
  67. LONG big_Left = 0, big_Top = 0, big_Width, big_Height ;
  68. STRPTR winTitle = "MemMinister 1.2" ;
  69. STRPTR fTitle   = "Total: %t" ;
  70. UBYTE *dPoint = "." ;
  71. LONG delaytime = DELAYTIME ;
  72. BOOL started_zoomed = FALSE, windowToBack = FALSE, savePosition = FALSE ;
  73.  
  74. VOID main( int argc, char **argv )
  75. {
  76.     struct Gadget *gad ;
  77.     struct DiskObject *dobj = NULL ;
  78.     STRPTR progName = (FROMWB ? ((struct WBStartup *)argv)->sm_ArgList->wa_Name : argv[0]) ;
  79.     struct TextFont *userfont = NULL ;
  80.     struct IntuiMessage *iMsg ;
  81.     ULONG chip_free, fast_free, class ;
  82.     UBYTE buf[200] ;
  83.     BOOL done = FALSE ;
  84.     
  85.     if( FROMWB || (argc > 1 && *argv[1] == '-') )
  86.         if( dobj = GetDiskObject(progName) )
  87.             userfont = setOptions( dobj ) ;
  88.     
  89.     if( scr = LockPubScreen( NULL ) )
  90.     {
  91.         /* layoutAll() initierar bla textattr => använd EJ textattr innan */
  92.         userfont = layoutAll( userfont ) ;
  93.         if( started_zoomed )
  94.         {
  95.             SWAP( big_Left,   zoomsize[0] ) ;
  96.             SWAP( big_Top,    zoomsize[1] ) ;   /*  ingen snygg lösning,   */
  97.             SWAP( big_Width,  zoomsize[2] ) ;   /*  men enkel...           */
  98.             SWAP( big_Height, zoomsize[3] ) ;
  99.         }
  100.         if( win = OpenWindowTags( NULL,
  101.             WA_Left,            big_Left,
  102.             WA_Top,             big_Top,
  103.             WA_Width,           big_Width,
  104.             WA_Height,          big_Height,
  105.             WA_Title,           winTitle,
  106.             WA_ScreenTitle,     "MemMinister 1.2  ©1994-1995 Marcus Ohlström",
  107.             WA_Gadgets,         &flush_gad,
  108.             WA_Zoom,            zoomsize,
  109.             WA_AutoAdjust,      TRUE,
  110.             WA_Flags,           WFLG_CLOSEGADGET | WFLG_DEPTHGADGET | WFLG_DRAGBAR,
  111.             WA_IDCMP,           IDCMP_CLOSEWINDOW | IDCMP_GADGETUP | IDCMP_NEWSIZE,
  112.             TAG_END ) )
  113.         {
  114.             if( windowToBack )
  115.                 WindowToBack( win ) ;
  116.             SetFont( win->RPort, userfont ) ; /* krävs, annars -> BUGG! */
  117.             writeInit() ; /* <= behövs egentligen inte om vi zip-startats */
  118.             writeSnapped( AvailMem(MEMF_CHIP), AvailMem(MEMF_FAST) ) ;
  119.             while( !done )
  120.             {
  121.                 if( !(win->Flags & WFLG_ZOOMED) ^ started_zoomed )
  122.                     writeFree( AvailMem(MEMF_CHIP), AvailMem(MEMF_FAST) ) ;
  123.                 else {
  124.                     chip_free  = AvailMem(MEMF_CHIP) ;
  125.                     fast_free  = AvailMem(MEMF_FAST) ;
  126.                     if(old_chip_free!=chip_free || old_fast_free!=fast_free)
  127.                     {
  128.                         formatTitle( fTitle, buf, chip_free, fast_free ) ;
  129.                         SetWindowTitles( win, buf, (UBYTE *)~0 ) ;
  130.                         old_chip_free  = chip_free  ;
  131.                         old_fast_free  = fast_free  ;
  132.                     }
  133.                 }
  134.                 Delay( delaytime ) ;
  135.                 
  136.                 /*   denna sats bör ligga här nedan för att programmet  */
  137.                 /*   inte ska vänta ytterligare delaytime*1/50 sec      */
  138.                 /*   efter IDCMP-meddelanden                            */
  139.                 while( iMsg = (struct IntuiMessage *)GetMsg( win->UserPort ) )
  140.                 {
  141.                     class = iMsg->Class ;
  142.                     gad   = (struct Gadget *)iMsg->IAddress ;
  143.                     /*  använd INTE gad om class != IDCMP_GADGETUP  */
  144.                     ReplyMsg( (struct Message *)iMsg ) ;
  145.  
  146.                     switch( class )
  147.                     {
  148.                         case IDCMP_GADGETUP:
  149.                                 switch( gad->GadgetID )
  150.                                 {
  151.                                     case FLUSH_GAD:
  152.                                         AllocMem( 0, 0 ) ;
  153.                                         break;
  154.                                     case SNAP_GAD:
  155.                                         writeSnapped( AvailMem(MEMF_CHIP), AvailMem(MEMF_FAST) ) ;
  156.                                         writeUsed( 0, 0 ) ;
  157.                                 }
  158.                                 break ;
  159.                         case IDCMP_NEWSIZE:
  160.                                 if( !(win->Flags & WFLG_ZOOMED) ^ started_zoomed )
  161.                                 {
  162.                                     SetWindowTitles( win, winTitle, (UBYTE *)~0 ) ;
  163.                                     writeInit() ;
  164.                                     writeSnapped( chip_snapped, fast_snapped ) ;
  165.                                 }
  166.                                 old_chip_free = old_fast_free = 0 ;
  167.                                 /* ^^ för att alla siffror ska uppdateras */
  168.                                 break;
  169.                         case IDCMP_CLOSEWINDOW:
  170.                                 done = TRUE ;
  171.                                 if(dobj && savePosition)
  172.                                     putToolTypes( dobj, progName, (!(win->Flags & WFLG_ZOOMED) ^ started_zoomed )) ;
  173.                     }
  174.                 }
  175.             }
  176.             CloseWindow( win ) ;
  177.         }
  178.         UnlockPubScreen( NULL, scr ) ;
  179.     }
  180.     
  181.     if( dobj )
  182.         FreeDiskObject( dobj ) ;
  183.     
  184.     if( userfont )
  185.         CloseFont( userfont ) ;
  186. }
  187.  
  188. struct TextFont *setOptions( struct DiskObject *dobj )
  189. {
  190.     struct TextFont *userfont = NULL ;
  191.     char **toolarray ;
  192.     UBYTE *str ;
  193.     LONG tmp ;
  194.     
  195.     toolarray = (char **)dobj->do_ToolTypes ;
  196.     
  197.     if( str = FindToolType(toolarray, "LEFT") )
  198.         StrToLong( str, &big_Left ) ;
  199.     
  200.     if( str = FindToolType(toolarray, "TOP") )
  201.         StrToLong( str, &big_Top ) ;
  202.     
  203.     if( str = FindToolType(toolarray, "ZIPLEFT") )
  204.     {
  205.         StrToLong( str, &tmp ) ;
  206.         zoomsize[0] = (WORD)tmp ;
  207.     }
  208.     
  209.     if( str = FindToolType(toolarray, "ZIPTOP") )
  210.     {
  211.         StrToLong( str, &tmp ) ;
  212.         zoomsize[1] = (WORD)tmp ;
  213.     }
  214.     
  215.     if( str = FindToolType(toolarray, "ZIPWIDTH") )
  216.     {
  217.         StrToLong( str, &tmp ) ;
  218.         zoomsize[2] = (WORD)tmp ;
  219.     }
  220.     
  221.     if( textattr.ta_Name = FindToolType(toolarray, "FONTNAME") )
  222.     {
  223.         if( str = FindToolType(toolarray, "FONTSIZE") )
  224.         {
  225.             StrToLong( str, &tmp ) ;
  226.             if( (textattr.ta_YSize = (UWORD)tmp) > 0 )
  227.                 userfont = OpenDiskFont( &textattr ) ;
  228.         }
  229.     }
  230.     
  231.     if( str = FindToolType(toolarray, "TITLEFORMAT") )
  232.         fTitle = str ;
  233.     
  234.     if( (str = FindToolType(toolarray, "DECIMALPOINT")) && *str != NULL )
  235.         dPoint = str ;
  236.     
  237.     if( str = FindToolType(toolarray, "DELAYTIME") )
  238.         StrToLong( str, &delaytime ) ;
  239.     
  240.     if( FindToolType(toolarray, "ZIPPED") )
  241.         started_zoomed = TRUE ;
  242.     
  243.     if( FindToolType(toolarray, "WINDOWTOBACK") )
  244.         windowToBack = TRUE ;
  245.     
  246.     if( FindToolType(toolarray, "SAVEPOSITION") )
  247.         savePosition = TRUE ;
  248.     
  249.     return( userfont ) ;
  250. }
  251.  
  252. struct TextFont *layoutAll( struct TextFont *userTFont )
  253. {
  254.     LONG chip_length, fast_length, total_length, max_length, flush_length ;
  255.     struct TextFont *scrTFont = scr->RastPort.Font ;
  256.     
  257.     if( !userTFont )
  258.     {
  259.         userTFont = scrTFont ;
  260.         
  261.         /* om userTFont != NULL är dessa fält redan satta (i setOptions()) */
  262.         textattr.ta_Name  = userTFont->tf_Message.mn_Node.ln_Name ;
  263.         textattr.ta_YSize = userTFont->tf_YSize ;
  264.     }
  265.     
  266.     number_length = digit_maxlength( userTFont ) ;
  267.     
  268.     if( zoomsize[2] < 65 )   /* giltigt värde i tooltypes? */
  269.         zoomsize[2] = 200 ;  /* nej! (200 ser bäst ut på topaz8-skärm) */
  270.         
  271.     zoomsize[3] = 3 + scrTFont->tf_YSize ;
  272.     
  273.     iText.IText = chip_text ;   chip_length  = IntuiTextLength( &iText ) ;
  274.     iText.IText = fast_text ;   fast_length  = IntuiTextLength( &iText ) ;
  275.     iText.IText = total_text ;  total_length = IntuiTextLength( &iText ) ;
  276.                                 flush_length = IntuiTextLength( &flush_gadText ) ;
  277.     
  278.     max_length = MAX( MAX(chip_length, fast_length), MAX(total_length, flush_length) ) ;
  279.     
  280.     big_Height = scr->WBorBottom + userTFont->tf_YSize +
  281.         (total_YPos = userTFont->tf_YSize +
  282.         (fast_YPos = userTFont->tf_YSize +
  283.         (chip_YPos = scr->WBorTop + 1 + userTFont->tf_YSize + scrTFont->tf_YSize + 3 + 1))) ;
  284.     
  285.     big_Width = scr->WBorRight + 4 +
  286.         (used_RightX = number_length +
  287.         (snapped_RightX = number_length +
  288.         (free_RightX = number_length +
  289.         (text_RightX = scr->WBorLeft + 2 + max_length)))) ;
  290.     
  291.     flush_gad.LeftEdge = scr->WBorLeft ;
  292.     flush_gad.TopEdge  = scrTFont->tf_YSize + 3 ;
  293.     flush_gad.Width    = 2 + max_length + 5 ;
  294.     flush_gad.Height   = userTFont->tf_YSize + 3 ;
  295.     
  296.     snap_gad.LeftEdge = scr->WBorLeft + flush_gad.Width ;
  297.     snap_gad.TopEdge  = flush_gad.TopEdge ;
  298.     snap_gad.Width    = big_Width - flush_gad.Width - scr->WBorLeft - scr->WBorRight ;
  299.     snap_gad.Height   = flush_gad.Height ;
  300.     
  301.     buildBoolBorder( &flush_gad ) ;
  302.     buildBoolBorder(  &snap_gad ) ;
  303.     
  304.     snap_gadText[0].LeftEdge = text_RightX    - flush_gad.Width + (number_length - IntuiTextLength(&snap_gadText[0]))/2 ;
  305.     snap_gadText[1].LeftEdge = free_RightX    - flush_gad.Width + (number_length - IntuiTextLength(&snap_gadText[1]))/2 ;
  306.     snap_gadText[2].LeftEdge = snapped_RightX - flush_gad.Width + (number_length - IntuiTextLength(&snap_gadText[2]))/2 ;
  307.     
  308.     image.Height = userTFont->tf_YSize ;
  309.     
  310.     chip_XPos  = text_RightX - chip_length  ;
  311.     fast_XPos  = text_RightX - fast_length  ;
  312.     total_XPos = text_RightX - total_length ;
  313.     
  314.     return( userTFont ) ;
  315. }
  316.  
  317. VOID writeInit( VOID )
  318. {
  319.     struct DrawInfo *di = GetScreenDrawInfo( win->WScreen ) ;
  320.     
  321.     iText.FrontPen = di ? di->dri_Pens[HIGHLIGHTTEXTPEN] : 2 ;
  322.     
  323.     iText.IText = chip_text ;
  324.     PrintIText( win->RPort, &iText, chip_XPos, chip_YPos ) ;
  325.     
  326.     iText.IText = fast_text ;
  327.     PrintIText( win->RPort, &iText, fast_XPos, fast_YPos ) ;
  328.     
  329.     iText.IText = total_text ;
  330.     PrintIText( win->RPort, &iText, total_XPos, total_YPos ) ;
  331.     
  332.     iText.FrontPen = di ? di->dri_Pens[TEXTPEN] : 1 ;
  333.     
  334.     iText.IText = str ;
  335. }
  336.  
  337. VOID writeFree( ULONG chip_free, ULONG fast_free )
  338. {
  339.     BOOL any_change = FALSE ;
  340.     
  341.     if( chip_free != old_chip_free )
  342.     {
  343.         myPrintINumber( chip_free, free_RightX, chip_YPos ) ;
  344.         old_chip_free = chip_free ;
  345.         any_change = TRUE ;
  346.     }
  347.     
  348.     if( fast_free != old_fast_free )
  349.     {
  350.         myPrintINumber( fast_free, free_RightX, fast_YPos ) ;
  351.         old_fast_free = fast_free ;
  352.         any_change = TRUE ;
  353.     }
  354.     
  355.     if( any_change )
  356.     {
  357.         myPrintINumber( chip_free + fast_free, free_RightX, total_YPos ) ;
  358.         
  359.         writeUsed( chip_snapped-chip_free, fast_snapped-fast_free ) ;
  360.     }
  361. }
  362.  
  363. VOID writeSnapped( ULONG chip_now, ULONG fast_now )
  364. {
  365.     myPrintINumber( chip_now, snapped_RightX, chip_YPos ) ;
  366.     myPrintINumber( fast_now, snapped_RightX, fast_YPos ) ;
  367.     myPrintINumber( chip_now + fast_now, snapped_RightX, total_YPos ) ;
  368.     chip_snapped = chip_now ;
  369.     fast_snapped = fast_now ;
  370. }
  371.  
  372. VOID writeUsed( ULONG chip_used, ULONG fast_used )
  373. {
  374.     myPrintINumber( chip_used, used_RightX, chip_YPos ) ;
  375.     myPrintINumber( fast_used, used_RightX, fast_YPos ) ;
  376.     myPrintINumber( chip_used+fast_used, used_RightX, total_YPos ) ;
  377. }
  378.  
  379. VOID myPrintINumber( ULONG number, ULONG XRight, ULONG Y )
  380. {
  381.     sprintf( iText.IText, "%ld", number ) ;
  382.     PrintIText( win->RPort, &iText, XRight-IntuiTextLength(&iText), Y ) ;
  383.     
  384.     image.Width = number_length - IntuiTextLength(&iText) ;
  385.     DrawImage( win->RPort, &image, XRight-number_length, Y ) ;
  386. }
  387.  
  388. /*  gad->GadgetRender->XY MÅSTE vara MEMF_CLEARed WORD[12]  */
  389. VOID buildBoolBorder( struct Gadget *gad )
  390. {
  391.     WORD *XY = ((struct Border *)gad->GadgetRender)->XY ;
  392.     
  393.     XY[1] = XY[9] = XY[11] = gad->Height - 1 ;
  394.     XY[4] = XY[6] = XY[8] = gad->Width - 1 ;
  395.     XY[10] = 1 ;
  396. }
  397.  
  398. LONG digit_maxlength( struct TextFont *Font )
  399. {
  400.     ULONG LoChar ;
  401.     LONG char_width = 0, tmp, count = 10 ;
  402.     
  403.     LoChar = Font->tf_LoChar ;
  404.     
  405.     if( FPF_PROPORTIONAL & Font->tf_Flags )
  406.     {
  407.         while( count-- )
  408.         {
  409.             tmp = ((WORD*)Font->tf_CharSpace)['0' - LoChar + count] + ((WORD*)Font->tf_CharKern )['0' - LoChar + count] ;
  410.             char_width = MAX( char_width, tmp ) ;
  411.         }
  412.         tmp = ((WORD*)Font->tf_CharSpace)['-' - LoChar] + ((WORD*)Font->tf_CharKern )['-' - LoChar] ;
  413.         tmp = MAX( char_width, tmp ) ;
  414.     } else
  415.         char_width = tmp = Font->tf_XSize ;
  416.     
  417.     return( char_width * (STRLEN-2) + tmp ) ; /* <- för att tänka på '-' */
  418. }
  419.  
  420. VOID formatTitle( STRPTR str, STRPTR buf, ULONG chip_free, ULONG fast_free )
  421. {
  422.     ULONG tmp, mod ;
  423.     BOOL doFormat = FALSE ;
  424.     
  425.     while( NULL != (*buf = *str) )
  426.     {
  427.         if( *str == '%' )
  428.         {
  429.             switch( *(++str) )
  430.             {
  431.                 case 'c':
  432.                 case 'C':   tmp = chip_free ;
  433.                             doFormat = TRUE ;
  434.                             break ;
  435.                 case 'f':
  436.                 case 'F':   tmp = fast_free ;
  437.                             doFormat = TRUE ;
  438.                             break ;
  439.                 case 't':
  440.                 case 'T':   tmp = chip_free + fast_free ;
  441.                             doFormat = TRUE ;
  442.                             break ;
  443.                 default:    *buf = *str ;
  444.             }
  445.             if( doFormat )
  446.             {
  447.                 switch( *(str+1) )
  448.                 {
  449.                     case 'm':
  450.                     case 'M':   tmp /= 1024 ;
  451.                     case 'k':
  452.                     case 'K':   mod = (((tmp % 1024) * 1000/1024) + 5) / 10 ;
  453.                                           /* för att få avrundning ^^^ */
  454.                                 tmp /= 1024 ;
  455.                                 sprintf( buf, "%ld%s%02.ld", tmp, dPoint, mod ) ;
  456.                                 str++ ;
  457.                                 break ;
  458.                     case 'b':
  459.                     case 'B':   str++ ;
  460.                     default:    sprintf( buf, "%ld", tmp ) ;
  461.                 }
  462.                 while( *(buf+1) != NULL ) buf++ ;
  463.                 doFormat = FALSE ;
  464.             }
  465.         }
  466.         buf++ ;
  467.         str++ ;
  468.     }
  469. }
  470.  
  471. VOID putToolTypes( struct DiskObject *dobj, STRPTR name, BOOL big_win )
  472. {
  473.     char **oldtt = dobj->do_ToolTypes ;
  474.     char *newtt[32] ;
  475.     UBYTE i ;
  476.     UBYTE left_str[14], top_str[13] ;
  477.     
  478.     for( i = 0 ; oldtt[i] && i < 32 ; i++ )
  479.         newtt[i] = oldtt[i] ;
  480.     
  481.     newtt[i] = NULL ;
  482.     
  483.     if( big_win )
  484.     {
  485.         sprintf( left_str, "LEFT=%ld", win->LeftEdge ) ;
  486.         sprintf( top_str,  "TOP=%ld",  win->TopEdge  ) ;
  487.         
  488.         newtt[ findToolType(newtt,"(LEFT=" ,6) ] = left_str   ;
  489.         newtt[ findToolType(newtt,"(TOP="  ,5) ] = top_str    ;
  490.         newtt[ findToolType(newtt,"(ZIPPED",7) ] = "(ZIPPED)" ;
  491.     } else {
  492.         sprintf( left_str, "ZIPLEFT=%ld", win->LeftEdge ) ;
  493.         sprintf( top_str,  "ZIPTOP=%ld",  win->TopEdge  ) ;
  494.         
  495.         newtt[ findToolType(newtt,"(ZIPLEFT=",9) ] = left_str ;
  496.         newtt[ findToolType(newtt,"(ZIPTOP=" ,8) ] = top_str  ;
  497.         newtt[ findToolType(newtt,"(ZIPPED"  ,7) ] = "ZIPPED" ;
  498.     }
  499.     
  500.     dobj->do_ToolTypes = newtt ;
  501.     PutDiskObject( name, dobj ) ;
  502.     dobj->do_ToolTypes = oldtt ;
  503. }
  504.  
  505. ULONG findToolType( char **tt, char *str, ULONG strlen )
  506. {
  507.     UBYTE i ;
  508.     
  509.     for( i = 0 ; tt[i] && i < 32 ; i++ )
  510.     {
  511.         if( !strnicmp( tt[i], str,   strlen   ) ) break ;
  512.         if( !strnicmp( tt[i], str+1, strlen-1 ) ) break ;
  513.     }
  514.     
  515.     if( i > 30 ) i = 30 ;
  516.     if( tt[i] == NULL ) tt[i+1] = NULL ;
  517.     
  518.     return( i ) ;
  519. }
  520.